package com.jiyongjun.component.sls;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.log.Client;
import com.aliyun.openservices.log.common.*;
import com.aliyun.openservices.log.exception.LogException;
import com.aliyun.openservices.log.request.CreateDashboardRequest;
import com.aliyun.openservices.log.request.GetDashboardRequest;
import com.aliyun.openservices.log.request.UpdateIndexRequest;
import com.aliyun.openservices.log.response.GetIndexResponse;
import com.jiyongjun.component.config.LogBootstrapConfig;
import com.jiyongjun.component.config.LogSwitch;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <h2></h2>
 * <h3>描述：</h3>
 *
 * @author yongjun.jyj
 * @since 2022/7/14 18:37
 */
@Component
@Slf4j
public class SlsInitializer implements InitializingBean {

    @Qualifier("logSlsClient")
    @Autowired
    private Client logSlsClient;
    @Autowired
    private LogBootstrapConfig logBootStrapConfig;

    @Override
    public void afterPropertiesSet() throws Exception {
        // 不启用时，直接跳过
        if (!logBootStrapConfig.getEnable()) {
            return;
        }

        String projectName = logBootStrapConfig.getSlsProject();
        String logStoreName = logBootStrapConfig.getSlsLogStore();
        // 1.检查项目
        createProjectIfAbsent(projectName);

        LogStore logStore = createLogStoreIfAbsent(projectName, logStoreName);

        createOrUpdateIndex(projectName, logStoreName, logStore);

        createDashboardIfAbsent(projectName, logStoreName, logBootStrapConfig.getEnv());
    }

    private void createProjectIfAbsent(String projectName) {
        try {
            logSlsClient.GetProject(projectName);
        } catch (LogException e) {
            try {
                logSlsClient.CreateProject(projectName, "自动创建日志项目，请手动修改项目描述");
            } catch (LogException ex) {
                // ignore
            }
        }
    }

    private LogStore createLogStoreIfAbsent(String projectName, String logStoreName) {
        LogStore logStore = new LogStore(logStoreName, 30, 2);
        logStore.setmAutoSplit(true);
        logStore.setmMaxSplitShard(64);
        logStore.setEnableWebTracking(true);
        try {
            logStore = logSlsClient.GetLogStore(projectName, logStoreName).GetLogStore();
        } catch (LogException e) {
            try {
                logSlsClient.CreateLogStore(projectName, logStore);
            } catch (LogException ex) {
                // ignore
            }
        }
        return null;
    }

    private void createOrUpdateIndex(String projectName, String logStoreName, LogStore logStore) throws LogException {
        Index index;
        try {
            GetIndexResponse getIndexResponse = logSlsClient.GetIndex(projectName, logStoreName);
            index = getIndexResponse.GetIndex();
            Map<String, IndexKey> oldKeys = index.GetKeys().GetKeys();
            int size = oldKeys.size();
            oldKeys.putAll(LogSwitch.SLS_LOG_INDEXS);
            if (oldKeys.size() > size) {
                this.logSlsClient.UpdateIndex(new UpdateIndexRequest(projectName, logStoreName, index));
            }
        } catch (LogException e) {
            if ("IndexConfigNotExist".equals(e.GetErrorCode())) {
                // 初始化索引
                index = new Index();
                index.SetTtl(logStore.GetTtl());
                index.setMaxTextLen(2048);
                IndexKeys keys = new IndexKeys();
                LogSwitch.SLS_LOG_INDEXS.forEach(keys::AddKey);
                index.SetKeys(keys);

                try {
                    this.logSlsClient.CreateIndex(projectName, logStoreName, index);
                } catch (LogException ex) {
                    // 多台机器同时启动，可能会多次创建，第二次创建会报错，忽略即可
                }
            } else {
                throw e;
            }
        }
    }

    private void createDashboardIfAbsent(String projectName, String logStoreName, String env) throws LogException{
        String dashboardName = "dashboard-" + logStoreName.toLowerCase() + "-exception_" + env;
        try {
            this.logSlsClient.getDashboard(new GetDashboardRequest(projectName, dashboardName));
        } catch (LogException e) {
            Dashboard dashboard = new Dashboard();
            dashboard.FromJsonString(LogSwitch.SLS_EXCEPTION_DASHBOARD);
            dashboard.setDashboardName(dashboardName);
            dashboard.setDisplayName(logStoreName + "接口报表(" + env + ")");
            AtomicInteger chatNo = new AtomicInteger(1);

            dashboard.getChartList().forEach(chart -> {
                chart.setLogstore(logStoreName);
                chart.setTitle(dashboardName + "-chat" + chatNo.getAndIncrement());
                // 修改search对象
                if (StringUtils.isNotBlank(chart.getRawSearchAttr())) {
                    JSONObject rawSearchAttrJsonObject = JSONObject.parseObject(chart.getRawSearchAttr());
                    rawSearchAttrJsonObject.put("logstore", logStoreName);
                    JSONArray chartQueries = rawSearchAttrJsonObject.getJSONArray("chartQueries");

                    if (chartQueries != null) {
                        chartQueries.forEach(chartQuery -> {
                            JSONObject chartQueryJson = (JSONObject) chartQuery;
                            chartQueryJson.put("logstore", logStoreName);
                            chartQueryJson.put("project", projectName);
                            if (chartQueryJson.get("query") != null) {
                                String query = chartQueryJson.getString("query");
                                query = query.replace("env: online", "env: " + env);
                                query = query.replace("env: pre", "env: " + env);
                                query = query.replace("env:online", "env:" + env);
                                query = query.replace("env:pre", "env:" + env);
                                chartQueryJson.put("query", StringEscapeUtils.unescapeJava(query));
                            }
                            if (chartQueryJson.get("tokenQuery") != null) {
                                String tokenQuery = chartQueryJson.getString("tokenQuery");
                                tokenQuery = tokenQuery.replace("env: online", "env: " + env);
                                tokenQuery = tokenQuery.replace("env: pre", "env: " + env);
                                tokenQuery = tokenQuery.replace("env:online", "env:" + env);
                                tokenQuery = tokenQuery.replace("env:pre", "env:" + env);
                                chartQueryJson.put("tokenQuery", StringEscapeUtils.unescapeJava(tokenQuery));
                            }
                        });
                    }
                    chart.setRawSearchAttr(rawSearchAttrJsonObject.toJSONString());
                }

                // 修改display对象
                if (StringUtils.isNotBlank(chart.getRawDisplayAttr())) {
                    JSONObject rawDisplayAttrJsonObject = JSONObject.parseObject(chart.getRawDisplayAttr());
                    JSONArray actionOptions = rawDisplayAttrJsonObject.getJSONArray("actionOptions");
                    if (actionOptions != null) {
                        actionOptions.forEach(actionOption -> {
                            JSONArray events = ((JSONObject) actionOption).getJSONArray("events");
                            if (events != null) {
                                events.forEach(event -> {
                                    JSONObject values = ((JSONObject) event).getJSONObject("values");
                                    if (values != null) {
                                        values.put("logstoreName", logStoreName);
                                        values.put("project", projectName);
                                        values.put("dashboardName", dashboardName);
                                        if (values.getString("searchFilter") != null) {
                                            String searchFilter = values.getString("searchFilter")
                                                    .replace("env: online", "env: " + env)
                                                    .replace("env:online", "env:" + env);
                                            values.put("searchFilter", searchFilter);
                                        }
                                    }
                                });
                            }
                        });
                    }

                    chart.setRawDisplayAttr(rawDisplayAttrJsonObject.toJSONString());
                }
            });

            try {
                this.logSlsClient.createDashboard(new CreateDashboardRequest(projectName, dashboard));
            } catch (LogException ex) {
                // 多台机器同时启动并创建会报错，忽略即可
            }
        }
    }

}
